(require 'init-funcs)

;; 三件套  vertico, orderless, consult
;; 实现mini buffer候选菜单的垂直化，并可以搜索补全mini buffer的各项命令
(use-package vertico
    :ensure t
    :hook (after-init . vertico-mode)
    :config
    (setq vertico-resize nil
        vertico-count 17
        vertico-cycle t)
    ;; Cleans up path when moving directories with shadowed paths syntax, e.g.
    ;; cleans ~/foo/bar/// to /, and ~/foo/bar/~/ to ~/.
    (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)
    (add-hook 'minibuffer-setup-hook #'vertico-repeat-save)
    (define-key vertico-map (kbd "C-j") 'vertico-next)
    (define-key vertico-map (kbd "C-'") 'vertico-quick-jump)
    (define-key vertico-map (kbd "C-k") 'vertico-previous)
    (define-key vertico-map [backspace] #'vertico-directory-delete-char)
    (define-key vertico-map (kbd "s-SPC") #'+vertico/embark-preview)
)

;; orderless 实现搜索补全的模糊化
(use-package orderless
    :ensure t
    :demand t
    :config
    (defvar +orderless-dispatch-alist
        '((?% . char-fold-to-regexp)
        (?! . orderless-without-literal)
        (?`. orderless-initialism)
        (?= . orderless-literal)
        (?~ . orderless-flex)))

    (defun +orderless-dispatch (pattern index _total)
        (cond
        ;; Ensure that $ works with Consult commands, which add disambiguation suffixes
        ((string-suffix-p "$" pattern)
        `(orderless-regexp . ,(concat (substring pattern 0 -1) "[\x100000-\x10FFFD]*$")))
        ;; File extensions
        ((and
        ;; Completing filename or eshell
        (or minibuffer-completing-file-name
            (derived-mode-p 'eshell-mode))
        ;; File extension
        (string-match-p "\\`\\.." pattern))
        `(orderless-regexp . ,(concat "\\." (substring pattern 1) "[\x100000-\x10FFFD]*$")))
        ;; Ignore single !
        ((string= "!" pattern) `(orderless-literal . ""))
        ;; Prefix and suffix
        ((if-let (x (assq (aref pattern 0) +orderless-dispatch-alist))
            (cons (cdr x) (substring pattern 1))
            (when-let (x (assq (aref pattern (1- (length pattern))) +orderless-dispatch-alist))
            (cons (cdr x) (substring pattern 0 -1)))))))

  ;; Define orderless style with initialism by default
  (orderless-define-completion-style +orderless-with-initialism
                                     (orderless-matching-styles '(orderless-initialism orderless-literal orderless-regexp)))

  (setq completion-styles '(orderless partial-completion)
        completion-category-defaults nil
        completion-category-overrides '((file (styles partial-completion)) ;; partial-completion is tried first
                                        (command (styles +orderless-with-initialism))
                                        (variable (styles +orderless-with-initialism))
                                        (symbol (styles +orderless-with-initialism)))
        orderless-component-separator #'orderless-escapable-split-on-space ;; allow escaping space with backslash!
        orderless-style-dispatchers '(+orderless-dispatch))
)

;; 相当于Swiper，搜索的增强 consult
;; (use-package consult
;;     :ensure t
;;     :defer t
;;     :init
;;     (if sys/win32p
;;         (progn
;;             (add-to-list 'process-coding-system-alist '("es" gbk . gbk))
;;             (add-to-list 'process-coding-system-alist '("explorer" gbk . gbk))
;;             (setq consult-locate-args (encode-coding-string "es.exe -i -p -r" 'gbk))))
;;     (advice-add #'multi-occur :override #'consult-multi-occur)
;;     (advice-add #'consult-line
;;               :around
;;               #'custom/consult-line
;;               '((name . "wrapper")))

;;     :config
;;     (global-set-key (kbd "M-y") 'consult-yank-pop)
;;     (setq ;; consult-project-root-function #'doom-project-root
;;         consult-narrow-key "<"
;;         consult-line-numbers-widen t
;;         consult-async-min-input 2
;;         consult-async-refresh-delay  0.15
;;         consult-async-input-throttle 0.2
;;         consult-async-input-debounce 0.1
;;         consult-line-start-from-top t)

;;     (consult-customize
;;     consult-ripgrep consult-git-grep consult-grep
;;     consult-bookmark consult-recent-file
;;     :preview-key (kbd "C-SPC"))

;;         (consult-customize
;;         consult-theme
;;         :preview-key (list (kbd "C-SPC") :debounce 0.5 'any))
;; )

(use-package consult
  :ensure t
  :bind (([remap imenu]                  . consult-imenu)
         ([remap goto-line]              . consult-goto-line)
         ([remap bookmark-jump]          . consult-bookmark)
         ([remap recentf-open-files]     . consult-recent-file)
         ([remap repeat-complex-command] . consult-complex-command)
         ([remap jump-to-register]       . consult-register-load)
         ([remap point-to-register]      . consult-register-store))
  :config
  (with-no-warnings
    (consult-customize consult-ripgrep consult-git-grep consult-grep
                       consult-bookmark
                       consult-recent-file
                       consult-buffer
                       :preview-key nil))

  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)
  :custom
  (consult-fontify-preserve nil)
  (consult-async-min-input 2)
  (consult-async-refresh-delay 0.15)
  (consult-async-input-throttle 0.2)
  (consult-async-input-debounce 0.1))

;;## consult-dir 允许将目录路径插入Emacs的mini buffer提示中
(use-package consult-dir
    :ensure t
    :defer t
    :bind (([remap list-directory] . consult-dir)
          :map vertico-map
          ("s-d" . consult-dir)))

;;which integrates Consult with Flycheck
;;整合 Consult 和 Flycheck flycheck 检查器 flymake
(use-package consult-flycheck
    :ensure t
    :after (consult flycheck))

;; embark 继承命令
(use-package embark
    :ensure t
    :defer t
    :init
    (setq which-key-use-C-h-commands nil
            ;; press C-h after a prefix key, it shows all the possible key bindings and let you choose what you want
            prefix-help-command #'embark-prefix-help-command)

    (setq
    embark-verbose-indicator-display-action
    '((display-buffer-at-bottom)
        (window-parameters (mode-line-format . none))
        (window-height . fit-window-to-buffer)))

    (define-key minibuffer-local-map (kbd "C-;") 'embark-act)
    (define-key minibuffer-local-map (kbd "C-c C-;") 'embark-export)
    (define-key minibuffer-local-map (kbd "C-c C-e") '+vertico/embark-export-write)

    (with-eval-after-load 'popwin
        (progn
        (push '(occur-mode :position right :width 100) popwin:special-display-config)
        (push '(grep-mode :position right :width 100) popwin:special-display-config)
        (push '(special-mode :position right :width 100) popwin:special-display-config)))

    (global-set-key (kbd "C-;") 'embark-act)

    :config
    (define-key minibuffer-local-map (kbd "C-'") #'embark-become)
    ;; list all the keybindings in this buffer
    (global-set-key (kbd "C-h B") 'embark-bindings)
    ;; add the package! target finder before the file target finder,
    ;; so we don't get a false positive match.
    :config
    (define-key embark-identifier-map "R" #'consult-ripgrep)
    (define-key embark-identifier-map (kbd "C-s") #'consult-line)
    ;; (define-key embark-region-map "D" 'youdao-dictionary-search-async)

    (define-key embark-file-map (kbd "E") #'consult-directory-externally)
    (define-key embark-file-map (kbd "U") #'consult-snv-unlock)
    (define-key embark-file-map (kbd "H") #'my-calculate-file-md5)
)

;; marginalia 配合 embark的使用
(use-package marginalia
    :ensure t
    :hook (after-init . marginalia-mode)
    :init
    :config)

(use-package embark-consult
    :ensure t
    :after (embark consult)
    :demand
    :config
    (add-hook 'embark-collect-mode-hook #'consult-preview-at-point-mode))

;; 使用wgrep
(use-package wgrep
    :commands wgrep-change-to-wgrep-mode
    :config (setq wgrep-auto-save-buffer t))

;; ;;dirvish
;; ;;https://github.com/alexluigit/dirvish
;; (use-package dirvish
;;     :ensure t)
(provide 'init-completion)